//////////////////////////////////////////////////////////////////////////

#ifndef _SERVERCONNECTIONIMPL_H_
#define _SERVERCONNECTIONIMPL_H_

//////////////////////////////////////////////////////////////////////////

#ifndef _CONNECTIONIMPL_H_
#include "connectionimpl.h"
#endif

#ifndef _BOOSTSERVICE_H_
#include "boostservice.h"
#endif

#include <map>

//////////////////////////////////////////////////////////////////////////

using boost::system::error_code;
using boost::asio::ip::tcp;
using boost::asio::ip::udp;
class InnerPacket;

//////////////////////////////////////////////////////////////////////////


/** Boost connection implementation for server
*
*  @author   Pasechnik Roman
*  @author   Anastasia Karpinska
*  @since    Jun 30th, 2009
*  @updated  Nov 17th, 2009
*/
class ServerConnectionImpl : public ConnectionImpl
{
//////////////////////////////////////////////////////////////////////////

public:

//////////////////////////////////////////////////////////////////////////


    /** Constructor */
    ServerConnectionImpl();


    /** Destructor */
    virtual ~ServerConnectionImpl();


//////////////////////////////////////////////////////////////////////////


    /** Send TCP */
    virtual void SendTCP( const NetworkPacket& _data );


    /** Send UDP */
    virtual void SendUDP( const NetworkPacket& _data );


//////////////////////////////////////////////////////////////////////////


    /** Accept new connection */
    virtual void Accept();


    /** Connect to server 
        (empty implementation here, this is for client only) */
    virtual void Connect( const char* _address );


    /** Close connection */
    virtual void Close();


//////////////////////////////////////////////////////////////////////////


    /** Is client connected to server */
    virtual bool IsConnected() const;


//////////////////////////////////////////////////////////////////////////

private:

//////////////////////////////////////////////////////////////////////////


    /** Start receive UDP packets */
    void StartReceiveTCP();


    /** Start receive TCP packets */
    static void StartReceiveUDP();


//////////////////////////////////////////////////////////////////////////


    /** Handle accept */
    void HandleAccept( const error_code& _error );


//////////////////////////////////////////////////////////////////////////


    /** Inner call, send TCP packet*/
    void SendTCPInner( const NetworkPacket& _data );


    /** Inner call, send UDP packet*/
    void SendUDPInner( const NetworkPacket& _data );


//////////////////////////////////////////////////////////////////////////


    /** Handle sent TCP packet */
    void HandleSendTCP( const error_code& _error,
                        size_t _bytesTransferred );


//////////////////////////////////////////////////////////////////////////


    /** Handle received TCP packet */
    void HandleRecvTCP( const error_code& _error,
                        size_t _bytesTransferred );


    /** Handle received regular TCP packet */
    void HandleRecvTCPRegular( const InnerPacket& _innerPacket );


//////////////////////////////////////////////////////////////////////////


    /** Handle received UDP packet */
    static void HandleRecvUDP( const error_code& _error,
                               size_t _bytesTransferred );


    /** Handle received regular UDP packet */
    static void HandleRecvUDPRegular( const InnerPacket& _innerPacket );


    /** Handle received connect UDP packet */
    static void HandleRecvUDPConnect( const InnerPacket& _innerPacket );


//////////////////////////////////////////////////////////////////////////

private:

//////////////////////////////////////////////////////////////////////////
//// Sockets
//////////////////////////////////////////////////////////////////////////


    /** TCP socket */
    tcp::socket m_TCPSocket;
    std::string m_TCPEndpointString;


    /** UDP socket [Singleton] */
    static udp::socket* GetUDPSocket();
    static udp::socket* m_UDPSocket;


    /** Get UDP endpoint by connection */
    static udp::endpoint GetUDPEndpoint( ServerConnectionImpl* _this );


    /** UDP endpoint for receiving packets */
    static udp::endpoint m_UDPRecvEndpoint;


////////////////////////////////////////////////////////////////////////////////
//// Connection establishment
////////////////////////////////////////////////////////////////////////////////


    /** TCP acceptor [Singleton] */
    static tcp::acceptor* GetTCPAcceptor();
    static tcp::acceptor* m_Acceptor;


    /* Send TCP endpoint to the client,
       client must confirm this endpoint by UDP */
    void SendTCPEndpointToClient();


    /** Set UDP established for this connection */
    void SetUDPEstablished();


    /** Is UDP established for this connection */
    bool m_UDPEstablished;


    /** Start accepting UDP connections */
    void StartUDPAccept();


    /** Tells if UDP accept started or stopped */
    static bool m_UDPAcceptStarted;


////////////////////////////////////////////////////////////////////////////////

private:

////////////////////////////////////////////////////////////////////////////////


    /** [Utility type]: Connections by endpoints */
    typedef std::map<udp::endpoint, ServerConnectionImpl*> ConnectionsByEndpoints;
    static ConnectionsByEndpoints m_ConnectionsByEndpoints;


    /** [Utility type]: Endpoints by connections */
    typedef std::map<ServerConnectionImpl*, udp::endpoint> EndpointsByConnections;
    static EndpointsByConnections m_EndpointsByConnections;


    /** [Utility type]: Connections by endpoints addresses */
    typedef std::map<std::string, ServerConnectionImpl*> ConnectionsByAddress;
    static ConnectionsByAddress m_ConnectionsByAddress;


//////////////////////////////////////////////////////////////////////////
};

//////////////////////////////////////////////////////////////////////////

#endif

//////////////////////////////////////////////////////////////////////////
